#include "jogo.h"
#include "pavilhao.h"
#include "jogador.h"
#include "campeonato.h"
#include "login.h"
#include "menu.h"
#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>

using namespace std;

//! Excepcao NaoExisteEquipa
/*! E lancada na funcao lerFicheiro quando se tenta ler a informacao de um jogo que contem equipas nao estao definidas */
class NaoExisteEquipa
{
};

void escreverFicheiro(vector<Equipa> &lista_equipas, vector<Jogo> &lista_jogos, vector<Campeonato> &lista_campeonatos)
{
    ofstream f_info("informacao.txt");

    f_info << lista_campeonatos.size() << endl;
    int tamanho = lista_campeonatos.size();

    // Percorrer campeonatos
    for (int k = 0; k != tamanho; k++) {

        //string ano = "2009";

        int ano = lista_campeonatos[k].getAno();

        // Ano campeonato
        f_info << ano << endl;
        // Numero de equipas
        f_info << lista_campeonatos[k].getNumeroEquipas() << endl;

        for (int i = 0; i != lista_campeonatos[k].getNumeroEquipas(); i++) {
            Equipa temp_equipa = lista_equipas[i];

            f_info << temp_equipa.getNomeEquipa() << endl;
            f_info << temp_equipa.getTreinador() << endl;
            f_info << temp_equipa.tamanhoPlantel() << endl;

            for (int j = 0; j != temp_equipa.tamanhoPlantel(); j++) {
                f_info << temp_equipa.getPlantel()[j].getNome() << endl;
                f_info << temp_equipa.getPlantel()[j].getIdade() << endl;
            }
        }

        // Numero de jogos realizados na epoca
        int n_jogos_realizados = lista_campeonatos[k].getNumeroJogos();

        //int n_jogos_realizados = lista_jogos.size();
        f_info << n_jogos_realizados << endl;

        for (int i = 0; i != n_jogos_realizados; i++) {
            Jogo temp_jogo = lista_jogos[i];
            f_info << temp_jogo.getLocal() << endl;
            f_info << temp_jogo.getArbitro() << endl;
            f_info << temp_jogo.getDia() << " " << temp_jogo.getMes() << endl;

            // E necessario guardar temporariamente as equipas para se poder aceder aos seus metodos
            Equipa* temp_eq1 = temp_jogo.getEquipa1();
            Equipa* temp_eq2 = temp_jogo.getEquipa2();

            f_info << temp_eq1->getNomeEquipa() << endl;
            f_info << temp_eq2->getNomeEquipa() << endl;

            f_info << temp_jogo.getResultado().equipa1 << " "
                   << temp_jogo.getResultado().equipa2 << endl;
        }

    }
}

void lerFicheiro(vector<Equipa> &lista_equipas, vector<Jogo> &lista_jogos, vector<Campeonato> &lista_campeonatos)
{
    /* A informacao contida no ficheiro informacao esta ordenada da seguinte forma:
       Numero de campeonatos na base de dados
       Ano da Epoca
       Numero de equipas que participaram no campeonato
       (Para cada equipa)
       Nome da equipa
       Nome do treinador
       Numero de jogadores
       (Para cada jogador)
       Nome do jogador
       Idade do jogador
       Numero de jogos realizados na epoca
       (Para cada jogo)
       Nome do pavilhao onde o jogo foi realizado
       Nome do arbitro
       Data a que o jogo foi realizado (dia mes)
       Nome Equipa1
       Nome Equipa2
       Resultado do jogo (equipa1 equipa2)
    */

    ifstream f_info("informacao.txt");

    // Obter numero de campeonatos no ficheiro
    string temp_string; // Esta string vai ser usada como passo intermedio para chamar a funcao atoi para converter uma string para um inteiro
    getline(f_info, temp_string);
    // TODO: Talvez estes atoi devessem de lancar uma excepcao se nao funcionarem de forma correcta?
    int numero_campionatos = atoi(temp_string.c_str());


    for (int k = 0; k != numero_campionatos; k++)
    {

        // Obter ano do campeonato
        getline(f_info, temp_string);
        int ano = atoi(temp_string.c_str());

        // Criar um campeonato com o ano obtido
        Campeonato temp_campeonato(ano);

        vector<Equipa> equipas_adicionar_actual_campeonato;

        // Obter a informacao sobre as equipas

        // Obter o numero de equipa que existem
        getline(f_info, temp_string);

        int numero_equipas = atoi(temp_string.c_str());

        // vector<Equipa> lista_equipas;

        for (int i = 0; i != numero_equipas; i++) {

            // Obter nome da equipa
            string nome_equipa;
            getline(f_info, nome_equipa);

            // Obter nome do treinador
            string treinador;
            getline(f_info, treinador);

            Equipa temp_equipa(treinador, nome_equipa);

            // Obter numero de jogadores da equipa
            getline(f_info, temp_string);

            int numero_jogadores = atoi(temp_string.c_str());

            for (int j = 0; j != numero_jogadores; j++) {

                // Obter nome do jogador
                string nome_jogador;
                getline(f_info, nome_jogador);

                // Obter idade do jogador
                getline(f_info, temp_string);

                int jog_idade = atoi(temp_string.c_str());

                // cout << nome_jogador << endl
                //      << jog_idade << endl;

                Jogador temp_jog1(nome_jogador, jog_idade);

                //lista_jogadores.push_back(temp_jog1);

                //temp_equipa.adicionarJogador(lista_jogadores.back());
                temp_equipa.adicionarJogador(temp_jog1);

            }

            lista_equipas.push_back(temp_equipa);
            equipas_adicionar_actual_campeonato.push_back(temp_equipa);
        }

        // cout << lista_equipas.back().getNomeEquipa() << endl;

        // Obter o numero de jogos contidos no ficheiro
        getline(f_info, temp_string);
        int numero_jogos = atoi(temp_string.c_str());

        // vector<Jogo> lista_jogos;

        for (int i = 0; i != numero_jogos; i++) {

            // Obter o local onde foi realizado o jogo e o arbitro
            string pavilhao;
            string arbitro;
            getline(f_info, pavilhao);
            getline(f_info, arbitro);

            // Obter o dia
            typedef string::size_type sst;

            getline(f_info, temp_string);

            sst pos_dia = temp_string.find(' ');
            string temp_dia = temp_string.substr(0, pos_dia);
            int dia = atoi(temp_dia.c_str());

            // Obter o mes
            string temp_mes = temp_string.substr(++pos_dia);
            int mes = atoi(temp_mes.c_str());

            // Obter o nome da equipa1 e equipa2
            string equipa1;
            string equipa2;
            getline(f_info, equipa1);
            getline(f_info, equipa2);

            bool found_eq1 = false;
            bool found_eq2 = false;

            Equipa* ptr_eq1 = 0;
            Equipa* ptr_eq2 = 0;

            for (vector<Equipa>::size_type j = 0; j != lista_equipas.size(); j++) {
                if (lista_equipas[j].getNomeEquipa() == equipa1) {
                    ptr_eq1 = &lista_equipas[j];
                    found_eq1 = true;
                }

                else if (lista_equipas[j].getNomeEquipa() == equipa2) {
                    ptr_eq2 = &lista_equipas[j];
                    found_eq2 = true;
                }
            }

            // TODO: Criar excepcao NaoExisteEquipa
            if (found_eq1 == false)
                throw NaoExisteEquipa();
            if (found_eq2 == false)
                throw NaoExisteEquipa();

            // Obter os resultados da equipa 1
            getline(f_info, temp_string);
            sst pos_result_eq1 = temp_string.find(' ');
            string temp_result_eq1 = temp_string.substr(0, pos_result_eq1);
            int result_eq1 = atoi(temp_result_eq1.c_str());

            // Obter os resultados da equipa 2
            string temp_result_eq2 = temp_string.substr(++pos_result_eq1);
            int result_eq2 = atoi(temp_result_eq2.c_str());

            // cout << pavilhao << endl
            //      << arbitro << endl
            //      << dia << " " << mes << endl
            //      << equipa1 << endl
            //      << equipa2 << endl
            //      << result_eq1 << " " << result_eq2 << endl;

            Jogo temp_jogo(pavilhao, arbitro, dia, mes, ptr_eq1, ptr_eq2,
                result_eq1, result_eq2);

            lista_jogos.push_back(temp_jogo);
            //temp_campeonato.adicionarJogo(&temp_jogo);
            temp_campeonato.adicionarJogo(&(*(lista_jogos.rbegin())));


        }


        // Adicionar as equipas ao campeonato
        // FIXME: Acabar isto
        //temp_campeonato.adicionarEquipa
        for (vector<Equipa>::size_type k = 0; k != equipas_adicionar_actual_campeonato.size(); k++) {
            for (vector<Equipa>::size_type j = 0; j != lista_equipas.size(); j++) {
                // Comparar equipas, para ver se vamos adicionar o apontador para a equipa certa
                if (equipas_adicionar_actual_campeonato[k] == lista_equipas[j]) {
                    temp_campeonato.adicionarEquipa(&lista_equipas[k]);
                    break;
                }
            }
        }

        lista_campeonatos.push_back(temp_campeonato);

    }
}

int main()
{
    vector<Equipa> lista_equipas;
    vector<Jogo> lista_jogos;
    vector<Campeonato> lista_campeonatos;

    /* HACK: impede que os vectores se desloquem muito na memoria (o que dava
     * cabo dos apontadores.
     * Estas estruturas deveriam de ser umas listas ligadas
     */
    lista_equipas.reserve(100);
    lista_jogos.reserve(100);
    lista_campeonatos.reserve(50);

    lerFicheiro(lista_equipas, lista_jogos, lista_campeonatos);


    cout << "       ____                            _           _                     " << endl
         << "      | __ )  ___ _ __ ___      __   _(_)_ __   __| | ___     __ _  ___  " << endl
         << "      |  _ \\ / _ \\ '_ ` _ \\ ____\\ \\ / / | '_ \\ / _` |/ _ \\   / _` |/ _ \\ " << endl
         << "      | |_) |  __/ | | | | |_____\\ V /| | | | | (_| | (_) | | (_| | (_) |" << endl
         << "      |____/ \\___|_| |_| |_|      \\_/ |_|_| |_|\\__,_|\\___/   \\__,_|\\___/ " << endl
         << "" << endl
         << "                                                                _      " << endl
         << "          _ __  _ __ ___   __ _ _ __ __ _ _ __ ___   __ _    __| | ___ " << endl
         << "         | '_ \\| '__/ _ \\ / _` | '__/ _` | '_ ` _ \\ / _` |  / _` |/ _ \\" << endl
         << "         | |_) | | | (_) | (_| | | | (_| | | | | | | (_| | | (_| |  __/" << endl
         << "         | .__/|_|  \\___/ \\__, |_|  \\__,_|_| |_| |_|\\__,_|  \\__,_|\\___|" << endl
         << "         |_|              |___/                                        " << endl
         << "                        _                _              " << endl
         << "                       | |__   ___   ___| | _____ _   _ " << endl
         << "                       | '_ \\ / _ \\ / __| |/ / _ \\ | | |" << endl
         << "                       | | | | (_) | (__|   <  __/ |_| |" << endl
         << "                       |_| |_|\\___/ \\___|_|\\_\\___|\\__, |" << endl
         << "                                                  |___/ " << endl;



    // Objecto que trata dos menus (incluindo logins)
    Menu menu_manager(lista_equipas, lista_jogos, lista_campeonatos);
    menu_manager.menu_principal();

    escreverFicheiro(lista_equipas, lista_jogos, lista_campeonatos);

    return 0;
}


int testes()
{
    vector<Equipa> lista_equipas;
    vector<Jogo>lista_jogos;
    vector<Campeonato> lista_campeonatos;

    lerFicheiro(lista_equipas, lista_jogos, lista_campeonatos);
    // Teste pavilhao
    Pavilhao temp("Estadio do Porto", 50000);

    try {
        Pavilhao temp_err("fsdf", -1000);
    }
    catch(CapacidadeImpossivel e) {
        cout << "Capacidade impossivel" << endl
             << "lugares: " << e.capacidade << endl;
    }
    ////////////////////

    // Teste Jogadores e Equipas
    Jogador jog1("Rolando", 30);
    Jogador jog2("Emanuel", 20);
    Jogador jog3("Fabio", 25);
    Jogador jog4("Rodrigues", 10);
    Jogador jog5("Pereira", 12);

    Equipa porto("Mourinho", "Futebol Clube do Porto");

    porto.adicionarJogador(jog1);
    porto.adicionarJogador(jog2);
    porto.adicionarJogador(jog3);
    porto.adicionarJogador(jog4);
    porto.adicionarJogador(jog5);

    porto.imprimir();

    porto.removerJogador("Rolando");
    cout << "Equipa depois de remover Rolando" << endl;

    porto.imprimir();

    // Mudar treinador
    cout << "Treinador antigo: " << porto.getTreinador() << endl;
    porto.mudarTreinador("Scolari");
    cout << "Novo treinador: " << porto.getTreinador() << endl;
    ///////////////////////

    Jogador j1("j1", 21);
    Jogador j2("j2", 22);
    Jogador j3("j3", 23);
    Jogador j4("j4", 24);
    Jogador j5("j5", 25);

    Equipa clube_j("Pedro Barbosa", "Clube dos Jotas");

    clube_j.adicionarJogador(j1);
    clube_j.adicionarJogador(j2);
    clube_j.adicionarJogador(j3);
    clube_j.adicionarJogador(j4);
    clube_j.adicionarJogador(j5);

    // Teste Jogo
    Jogo jogo1("Pavilhao Rosa mota", "Bruno Chaves", 10, 20, &porto, &clube_j, 4, 2);

    // FIXME: Nao consigo usar o ostream& aqui porque?
    jogo1.imprimir();
    ///////////////

    // Teste campionato
    Campeonato epoca09_10(2009);

    epoca09_10.adicionarEquipa(&porto);
    epoca09_10.adicionarEquipa(&clube_j);

    epoca09_10.imprimir();
    /////

    return 0;
}
